// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.designer.core.codegen;

import java.util.Collections;
import java.util.Vector;

import org.apache.log4j.Logger;
import org.dengues.commons.ui.swt.colorstyledtext.EModeLanguage;
import org.dengues.core.CorePlugin;
import org.dengues.core.codegen.ICodeGenerator;
import org.dengues.core.components.EJETCodePart;
import org.dengues.core.components.IComponentFilesNaming;
import org.dengues.core.components.IComponentsFactory;
import org.dengues.core.components.IXMLComponent;
import org.dengues.core.prefs.IDenguesPrefsConstant;
import org.dengues.core.process.ICompConnection;
import org.dengues.core.process.ICompNode;
import org.dengues.core.process.ICompProcess;
import org.dengues.core.process.ICompSubProcess;
import org.dengues.designer.core.DesignerCorePlugin;
import org.dengues.designer.core.codegen.config.EInternalJETTemplate;
import org.dengues.designer.core.codegen.config.JETCodeGeneratorArgument;
import org.dengues.designer.core.codegen.config.JETCodeGeneratorEmittersPoolFactory;
import org.dengues.designer.core.codegen.config.JETTemplateBean;
import org.dengues.designer.core.codegen.config.JETTemplateUtil;
import org.dengues.designer.core.components.ComponentFilesNaming;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.emf.codegen.jet.JETEmitter;
import org.osgi.framework.Constants;

/**
 * Qiang.Zhang.Adolf@gmail.com class global comment. Detailled comment <br/>
 * 
 * $Id: Dengues.epf 1 2006-09-29 17:06:40Z qiang.zhang $
 * 
 */
public class ProcessCodeGenerator implements ICodeGenerator {

    private static Logger log = Logger.getLogger(ProcessCodeGenerator.class);

    private ICompProcess process;

    private IPath path;

    /**
     * Qiang.Zhang.Adolf@gmail.com ProcessCodeGenerator constructor comment.
     */
    public ProcessCodeGenerator() {
        super();
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com ProcessCodeGenerator constructor comment.
     * 
     * @param process
     * @param path
     */
    public ProcessCodeGenerator(ICompProcess process, IPath path) {
        this.process = process;
        this.path = path;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.core.codegen.ICodeGenerator#generateComponentCode(org.dengues.core.process.ICompNode,
     * org.dengues.core.components.EJETCodePart)
     */
    public String generateComponentCode(ICompNode compNode, EJETCodePart part) {
        JETCodeGeneratorArgument argument = new JETCodeGeneratorArgument();
        argument.setArgument(compNode);
        argument.setCodePart(part);
        argument.setSocketTimeSpacing(CorePlugin.getDefault().getPreferenceStore().getInt(
                IDenguesPrefsConstant.SOCKET_TIME_SPACING));
        argument.setSocketPort(CorePlugin.getDefault().getPreferenceStore().getInt(IDenguesPrefsConstant.SOCKET_PORT));

        JETTemplateBean jetBean = initializeJetBean(argument);
        StringBuffer content = new StringBuffer();
        IXMLComponent node = compNode.getComponent();
        try {
            IComponentFilesNaming componentFileNaming = new ComponentFilesNaming();
            String templateURI = node.getPathSource() + JETTemplateUtil.DIR_SEP + node.getName() + JETTemplateUtil.DIR_SEP
                    + componentFileNaming.getJetFileName(node, EModeLanguage.JAVA.getLanguageMode(), part);

            jetBean.setTemplateRelativeUri(templateURI);
            content.append(generate(jetBean));
            return content.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ""; //$NON-NLS-1$
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "initializeJetBean".
     * 
     * @param argument
     * @return
     */
    private JETTemplateBean initializeJetBean(JETCodeGeneratorArgument argument) {
        JETTemplateBean jetBean = new JETTemplateBean();
        jetBean.setJetPluginRepository(IComponentsFactory.COMPONENTS_LOCATION);
        jetBean.setArgument(argument);
        return jetBean;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "generate".
     * 
     * @param bean
     * @return
     */
    private String generate(JETTemplateBean bean) {
        JETEmitter emitter = JETCodeGeneratorEmittersPoolFactory.getEmitterPool().get(bean);
        IProgressMonitor sub = new SubProgressMonitor(new NullProgressMonitor(), 1);
        String res = ""; //$NON-NLS-1$
        try {
            if (emitter != null) {
                res = emitter.generate(sub, new Object[] { bean.getArgument() });
                sub.worked(1);
            }
        } catch (Exception e) {
            log.error("generate Code Exception: ", e); //$NON-NLS-1$
        }
        return res;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.dengues.core.codegen.ICodeGenerator#generateProcessCode()
     */
    @SuppressWarnings("unchecked")//$NON-NLS-1$
    public String generateProcessCode() {
        StringBuffer componentsCode = new StringBuffer();
        Vector headerArgument = new Vector(3);
        headerArgument.add(process);
        headerArgument.add(DesignerCorePlugin.getDefault().getBundle().getHeaders().get(Constants.BUNDLE_VERSION));
        headerArgument.add(getPath());
        componentsCode.append(generateTypedComponentCode(EInternalJETTemplate.HEADER, headerArgument));
        Vector footerArgument = new Vector(2);
        footerArgument.add(process);
        footerArgument.add(Collections.EMPTY_LIST);
        for (ICompSubProcess subProc : process.getCompSubProcesses()) {
            ICompNode rootNode = subProc.getRootNode();
            componentsCode.append(generateTypedComponentCode(EInternalJETTemplate.SUBPROCESS_HEADER, rootNode));
            componentsCode.append(generateComponentsCode(subProc, rootNode, EJETCodePart.BEGIN));
            componentsCode.append(generateTypedComponentCode(EInternalJETTemplate.COMPONENT_HEADER, rootNode));
            componentsCode.append(generateComponentsCode(subProc, rootNode, EJETCodePart.MAIN));
            componentsCode.append(generateTypedComponentCode(EInternalJETTemplate.COMPONENT_FOOTER, rootNode));
            componentsCode.append(generateComponentsCode(subProc, rootNode, EJETCodePart.END));
            componentsCode.append(generateTypedComponentCode(EInternalJETTemplate.SUBPROCESS_FOOTER, rootNode));
        }
        footerArgument = new Vector(2);
        footerArgument.add(process);
        footerArgument.add(process.getRootCompNodes());
        componentsCode.append(generateTypedComponentCode(EInternalJETTemplate.FOOTER, footerArgument));
        componentsCode.append(generateTypedComponentCode(EInternalJETTemplate.PROCESSINFO, componentsCode.length()));
        return componentsCode.toString();
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getPath".
     * 
     * @return
     */
    private String getPath() {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < path.segmentCount(); i++) {
            builder.append("." + path.segment(i).replaceAll(" ", "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
        }
        return builder.toString();
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "generateComponentsCode".
     * 
     * @param subProc
     * @param rootNode
     * @param part
     * @return
     */
    private StringBuffer generateComponentsCode(ICompSubProcess subProc, ICompNode rootNode, EJETCodePart part) {
        StringBuffer codeComponent = new StringBuffer();
        switch (part) {
        case BEGIN:
            codeComponent.append(generatesSubProcessCode(subProc, rootNode, part));
            codeComponent.append(generateComponentCode(rootNode, EJETCodePart.BEGIN));
            break;
        case MAIN:

            codeComponent.append(generateComponentCode(rootNode, EJETCodePart.MAIN));

            codeComponent.append(generatesSubProcessCode(subProc, rootNode, part));
            break;
        case END:
            codeComponent.append(generateComponentCode(rootNode, EJETCodePart.END));
            codeComponent.append(generatesSubProcessCode(subProc, rootNode, part));
            break;
        default:
            // do nothing
        }
        return codeComponent;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "generatesSubProcessCode".
     * 
     * @param subProcess
     * @param node
     * @param part
     * @return
     */
    private StringBuffer generatesSubProcessCode(ICompSubProcess subProcess, ICompNode node, EJETCodePart part) {
        StringBuffer code = new StringBuffer();
        if (node != null) {
            for (ICompConnection connection : node.getOutgoingConnections()) {
                ICompNode targetNode = connection.getTarget();
                if ((targetNode != null) && (subProcess != null)) {
                    code.append(generateComponentsCode(subProcess, targetNode, part));
                }
            }
        }
        return code;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "generateTypedComponentCode".
     * 
     * @param template
     * @param argument
     * @return
     */
    private StringBuffer generateTypedComponentCode(EInternalJETTemplate template, Object argument) {
        JETCodeGeneratorArgument codeGenArgument = new JETCodeGeneratorArgument();
        codeGenArgument.setArgument(argument);
        codeGenArgument.setSocketTimeSpacing(CorePlugin.getDefault().getPreferenceStore().getInt(
                IDenguesPrefsConstant.SOCKET_TIME_SPACING));
        codeGenArgument.setSocketPort(CorePlugin.getDefault().getPreferenceStore().getInt(IDenguesPrefsConstant.SOCKET_PORT));

        JETTemplateBean jetBean = initializeJetBean(codeGenArgument);
        jetBean.setTemplateRelativeUri(JETTemplateUtil.RESOURCES_DIRECTORY + JETTemplateUtil.DIR_SEP + template
                + JETTemplateUtil.EXT_SEP + EModeLanguage.JAVA.getLanguageMode() + JETTemplateUtil.TEMPLATE_EXT);
        StringBuffer content = new StringBuffer();
        content.append(generate(jetBean));
        return content;
    }
}
